package com.woniuxy.stream;

import org.junit.Test;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamDemo {

    public static void main(String[] args) {

    }

    /**
     * TODO:	我们可以调用getAuthors方法获取到作家的集合。现在需要打印所有年龄小于18的作家的名字，并且要注意去重。
     *          必须要有终结操作 中间的操作才会最终生效
     **/
    @Test
    public void m1() {
        List<Author> authors = getAuthors();
        authors.stream().distinct(). //去除重复项
                filter(author -> {
            System.out.println("test");
            return author.getAge() < 18;
        }).//过滤条件
                forEach(author -> System.out.println(author.getName())); //打印输出 终结操作
    }

    /**
     * TODO:数组 单列集合 双列集合 转换为 Stream 来操作
     *          单列集合 直接调用Collection的方法 stream()来转换
     *          双列集合 先转换为单列集合 再来转换
     **/
    @Test
    public void m2() {
        //TODO 单列集合
        List<Author> authors = getAuthors();
        Stream<Author> stream = authors.stream();

        //TODO 数组
        Integer[] arr = {1, 2, 3, 4, 5};
        //Stream<Integer> arr1 = Arrays.stream(arr);
        Stream<Integer> arr1 = Stream.of(arr);
        arr1.distinct()
                .filter(integer -> integer % 2 != 0)
                .forEach(integer -> System.out.println(integer));


        //TODO 双列集合
        Map<String, Integer> map = new HashMap<>();
        map.put("蜡笔小新", 19);
        map.put("黑子", 17);
        map.put("日向翔阳", 16);

        Set<Map.Entry<String, Integer>> entries = map.entrySet();
        Stream<Map.Entry<String, Integer>> stream1 = entries.stream();
        stream1.filter(entry -> entry.getKey().length() > 2)
                .forEach(entry -> System.out.println(entry.getKey() + "------" + entry.getValue()));

        map.keySet().stream().filter(s -> s.startsWith("黑")).forEach(s -> System.out.println(s));
    }

    /**
     * TODO:中间操作 filter
     **/
    @Test
    public void m3() {
        //todo 打印所有姓名长度大于1的作家的姓名
        List<Author> authors = getAuthors();
        authors.stream().distinct().filter(author -> author.getName().length() > 1)
                .forEach(author -> System.out.println(author.getName()));
    }

    /**
     * TODO: map 对数据进行转换或者计算
     **/
    @Test
    public void m4() {
        //todo 打印所有作家的姓名
        List<Author> authors = getAuthors();
//        authors.stream().forEach(author -> System.out.println(author.getName()));

//        authors.stream().map(author -> author.getName())
//                .forEach(authorName-> System.out.println(authorName));


        authors.stream()
                .map(author -> author.getAge())
                .map(age -> age - 10)
                .forEach(age -> System.out.println(age));
    }

    /**
     * TODO:sorted 排序接口
     **/
    @Test
    public void m5() {
        //todo 	对流中的元素按照年龄进行降序排序，并且要求不能有重复的元素。
        List<Author> authors = getAuthors();
//        authors.stream()
//                .distinct()
//                .sorted()
//                .forEach(author -> System.out.println(author.getName()));
        authors.stream()
                .distinct()
                .sorted((o1, o2) -> o2.getAge() - o1.getAge())
                .forEach(author -> System.out.println(author.getAge()));

    }

    /**
     * TODO:limit 截取指定的长度
     **/
    @Test
    public void m6() {
        List<Author> authors = getAuthors();
        //todo 	对流中的元素按照年龄进行降序排序，并且要求不能有重复的元素,然后打印其中年龄最大的两个作家的姓名。
        authors.stream()
                .distinct()
                .sorted((o1, o2) -> o2.getAge() - o1.getAge())
                .limit(2)
                .forEach(author -> System.out.println(author.getName() + "----" + author.getAge()));
    }

    /**
     * TODO:skip 跳过流中指定数量的元素
     **/
    @Test
    public void m7() {
        List<Author> authors = getAuthors();
        //todo 打印除了年龄最大的作家外的其他作家，要求不能有重复元素，并且按照年龄降序排序。
        authors.stream()
                .distinct()
                .sorted((o1, o2) -> o2.getAge() - o1.getAge())
                .skip(1)
                .forEach(author -> System.out.println(author.getName() + author.getAge()));
    }

    /**
     * TODO: flatMap 可以把一个对象转成多个对象
     **/
    @Test
    public void m8() {
        List<Author> authors = getAuthors();
        //todo 	打印所有书籍的名字。要求对重复的元素进行去重。

//        authors.stream()
//                .map(author -> author.getBooks())
//                .forEach(books -> System.out.println(books));
        authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .forEach(book -> System.out.println(book.getName()));
    }

    @Test
    public void m9() {
        //todo 打印现有数据的所有分类。要求对分类进行去重。不能出现这种格式：哲学,爱情
        List<Author> authors = getAuthors();
        authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .flatMap(book -> Arrays.stream(book.getCategory().split(",")))
                .distinct()
                .forEach(str -> System.out.println(str));
    }

    /**
     * TODO:终结操作 count 计数
     **/
    @Test
    public void m10() {
        //todo 	打印这些作家的所出书籍的数目，注意删除重复元素。
        List<Author> authors = getAuthors();
        long count = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .count();
        System.out.println(count);
    }

    /**
     * TODO:终结操作 max/min 返回最大最小
     **/
    @Test
    public void m11() {
        //todo 分别获取这些作家的所出书籍的最高分和最低分并打印。
        List<Author> authors = getAuthors();
        Optional<Integer> max = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .map(book -> book.getScore())
                .max(((o1, o2) -> o1 - o2));
        System.out.println(max.get());

        Book book = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .min((o1, o2) -> o1.getScore() - o2.getScore())
                .get();
        System.out.println(book);
    }


    /**
     * TODO: collect 把当前流转换为集合 toList()
     **/
    @Test
    public void m12() {
        List<Author> authors = getAuthors();
        //todo 获取一个存放所有作者名字的List集合。
        List<String> collect = authors.stream()
                .map(author -> author.getName())
                .distinct()
                .collect(Collectors.toList());
        System.out.println(collect);
    }

    /**
     * TODO:Collectors.toSet
     **/
    @Test
    public void m13() {
        List<Author> authors = getAuthors();
        //todo 获取一个所有书名的Set集合。
        Set<String> collect = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .map(book -> book.getName())
                .distinct()
                .collect(Collectors.toSet());
        System.out.println(collect);
    }

    /**
     * TODO: Collectors.toMap 集合key不能重复
     **/
    @Test
    public void m14() {
        List<Author> authors = getAuthors();
        //todo 	获取一个Map集合，map的key为作者名，value为List<Book>
//        Map<String, List<Book>> collect = authors.stream()
//                .distinct()
//                .collect(Collectors.toMap(new Function<Author, String>() {
//                    @Override
//                    public String apply(Author author) {
//                        return author.getName();
//                    }
//                }, new Function<Author, List<Book>>() {
//                    @Override
//                    public List<Book> apply(Author author) {
//                        return author.getBooks();
//                    }
//                }));

        Map<String, List<Book>> collect = authors.stream()
                .distinct()
                .collect(Collectors.toMap(
                        author -> author.getName(),
                        author -> author.getBooks()
                ));

        collect.entrySet()
                .stream()
                .flatMap(entry -> entry.getValue().stream())
                .forEach(book -> System.out.println(book));


    }

    /**
     * TODO: anyMatch 是否有一个匹配
     **/
    @Test
    public void m15() {
        List<Author> authors = getAuthors();
        //todo 判断是否有年龄在29以上的作家
        System.out.println(authors.stream()
                .anyMatch(author -> author.getAge() > 88));

    }

    /**
     * TODO: allMatch 是否都满足
     **/
    @Test
    public void m16() {
        List<Author> authors = getAuthors();
        //todo 	判断是否所有的作家都是成年人
        boolean b = authors.stream()
                .allMatch(author -> author.getAge() > 18);
        System.out.println(b);
    }

    /**
     * TODO: noneMatch 是否都不满足
     **/
    @Test
    public void m17() {
        //todo 	判断作家是否都没有超过100岁的。
        boolean b = getAuthors().stream()
                .noneMatch(author -> author.getAge() > 100);
        System.out.println(b);
    }

    /**
     * TODO: findFirst 返回第一个元素
     **/
    @Test
    public void m18() {
        //todo 获取一个年龄最小的作家，并输出他的姓名。
        Optional<Author> first = getAuthors().stream()
                .sorted(((o1, o2) -> o2.getAge() - o1.getAge()))
                .filter(author -> author.getAge() > 100)
                .findFirst();
        first.ifPresent(author -> System.out.println(author.getName()));
    }

    /**
     * TODO:reduce 流中的数据按照你指定的计算方式计算出一个结果
     *          reduce的作用是把stream中的元素给组合起来，我们可以传入一个初始值，
     *          它会按照我们的计算方式依次拿流中的元素和初始化值进行计算，计算结果再和后面的元素计算
     **/
    @Test
    public void m19() {
        //todo 	使用reduce求所有作者年龄的和
        List<Author> authors = getAuthors();
        Integer ages = authors.stream()
                .distinct()
                .map(author -> author.getAge())
                .reduce(0, (age1, age2) -> age1 + age2);
        System.out.println(ages);
    }

    @Test
    public void m20() {
        //todo 	使用reduce求所有作者中年龄的最大值
        List<Author> authors = getAuthors();
//        Optional<Author> max = authors.stream()
//                .distinct()
//                .max((o1, o2) -> o1.getAge() - o2.getAge());
//        System.out.println(max.get());

        Integer reduce = authors.stream()
                .distinct()
                .map(author -> author.getAge())
                //.reduce(Integer.MIN_VALUE, (integer, integer2) -> Math.max(integer, integer2));
                //  .reduce(Integer.MIN_VALUE,(age1,age2)->age1>age2 ? age1 : age2);
                .reduce(Integer.MAX_VALUE, (age1, age2) -> age1 < age2 ? age1 : age2);
        System.out.println(reduce);
    }

    @Test
    public void m21() {
        //todo 单参数reduce
        //初始值会自动定义为第一个值
        List<Author> authors = getAuthors();
//        Optional<Integer> reduce = authors.stream()
//                .distinct()
//                .map(author -> author.getAge())
//                .reduce((age1, age2) -> age1 > age2 ? age1 : age2);
//        reduce.ifPresent(age-> System.out.println(age));


        Optional<Author> reduce = authors.stream()
                .distinct()
                .filter(author -> author.getBooks().size() > 2)
                .reduce((author1, author2) -> author1.getAge() > author1.getAge() ? author1 : author2);
        reduce.ifPresent(author -> System.out.println(author));


        authors.stream()
                .distinct()
                .map(author -> author.getBooks().size())
                .sorted(Comparator.comparingInt(o -> o))
                .collect(Collectors.toList())
                .stream()
                .forEach(size -> System.out.println(size));

    }

    @Test
    public void m22() {
        OptionalInt reduce = getAuthors().stream()
                .mapToInt(Author::getAge)
                .filter(age -> age > 18)
                .reduce(Integer::sum);
    }


    private static List<Author> getAuthors() {
        //数据初始化
        Author author = new Author(1L, "蒙多", 33, "一个从菜刀中明悟哲理的祖安人", null);
        Author author2 = new Author(2L, "亚拉索", 15, "狂风也追逐不上他的思考速度", null);
        Author author3 = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);
        Author author4 = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);

        //书籍列表
        List<Book> books1 = new ArrayList<>();
        List<Book> books2 = new ArrayList<>();
        List<Book> books3 = new ArrayList<>();

        books1.add(new Book(1L, "刀的两侧是光明与黑暗", "哲学,爱情", 88, "用一把刀划分了爱恨"));
        books1.add(new Book(2L, "一个人不能死在同一把刀下", "个人成长,爱情", 99, "讲述如何从失败中明悟真理"));

        books2.add(new Book(3L, "那风吹不到的地方", "哲学", 85, "带你用思维去领略世界的尽头"));
        books2.add(new Book(3L, "那风吹不到的地方", "哲学", 85, "带你用思维去领略世界的尽头"));
        books2.add(new Book(4L, "吹或不吹", "爱情,个人传记", 56, "一个哲学家的恋爱观注定很难把他所在的时代理解"));

        books3.add(new Book(5L, "你的剑就是我的剑", "爱情", 56, "无法想象一个武者能对他的伴侣这么的宽容"));
        books3.add(new Book(6L, "风与剑", "个人传记", 100, "两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢？"));
        books3.add(new Book(6L, "风与剑", "个人传记", 100, "两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢？"));

        author.setBooks(books1);
        author2.setBooks(books2);
        author3.setBooks(books3);
        author4.setBooks(books3);

        List<Author> authorList = new ArrayList<>(Arrays.asList(author, author2, author3, author4));
        return authorList;
    }
}
